.text
.code32

    mov $0x10, %ax
    mov %ax, %ds
    mov %ax, %es

    lgdt gdtr


# 填充二级页表
    mov $0x32000, %edi
    mov $0x33000 + 3, %eax
1:
    stosl
    add $0x1000, %eax
    add $4, %edi

    cmp $(0x32000 + 32 * 8 - 8), %edi
    jle 1b


# 填充一级页表
    mov $0x33000, %edi
    mov $0x0 + 3, %eax
2:
    stosl
    add $0x1000, %eax
    add $4, %edi

    cmp $(0x33000 + 512 * 32 * 8 - 8), %edi
    jle 2b


# 切入64位模式, 4个步骤
    # 4-1 Enable PAE
    mov %cr4, %eax
    btsl $5, %eax
    movl %eax, %cr4

    # 4-2 Setup cr3
    movl  $0x30000, %eax
    movl  %eax, %cr3

    # Setup EFER
    movl  $0xc0000080, %ecx
    rdmsr
    # Enable Long Mode
    btsl  $8, %eax
    # Enable syscall/sysret
    btsl  $0, %eax
    wrmsr

    # 4-4 开启分页
    mov %cr0, %eax
    bts $31, %eax
    mov %eax, %cr0

    ljmp $0x8, $0x100000

gdt:
    .quad 0x0000000000000000
    .quad 0x00209a0000000000
    .quad 0x0000920000000000
gdt_end:

gdtr:
    .word gdt_end - gdt
    .long gdt


# 下面四个页表用于虚拟地址 0xffffffff80000000 映射到物理地址 0x0000000000000000
# 1个四级页表, 每个页表中有512个页表项, 每个页表项指向一个三级页表
# 页表本身占用 512 * 8 = 4KB (0x1000)
.org 0x10000
    .quad 0x0000000000053003
    .fill 510, 8, 0
    .quad 0x0000000000031003

# 1个三级页表, 每个页表中有512个页表项, 每个页表项指向一个二级页表
# 页表本身占用 512 * 8 = 4KB (0x1000)
.org 0x11000
    .fill 510, 8, 0
    .quad 0x0000000000032003
    .fill 1, 8, 0

# 1个二级页表, 每个页表中有512个页表项, 每个页表项指向一个一级页表
# 页表本身占用 512 * 8 = 4KB (0x1000)
.org 0x12000
    .fill 512, 8, 0

# 32个一级页表, 每个页表中有512个页表项, 每个页表项指向一个4K的内存页面, 所以32个一级页表可以对应 32 * 512 * 4K = 64M内存
# 页表本身占用 512 * 8 * 32 = 128KB (0x20000)
.org 0x13000
    .fill 512 * 32, 8, 0


# 下面两个页表, 配合上面的四级页表和一级页表, 用于建立恒等映射
# 1个三级页表
.org 0x33000
    .quad 0x0000000000054003
    .fill 511, 8, 0

# 1个二级页表
.org 0x34000
    .quad 0x0000000000033003
    .fill 511, 8, 0



